;*****************************************************************************************************
;+
; NAME:
;
;      eCONTOUR (enhanced CONTOUR)
;
; PURPOSE:
;
;      This is the enhanced version of the standard IDL CONTOUR
;      command. It uses the same syntax and support most of the IDL
;      plotting keywords. The output contour plot is displayed in an IGL window
;      so that you can easily interact with it.
;
;      NOTE: The contour plot always has exact axis ranges. Extended ranges as
;            calculated by IDL would prevent the pan and zoom interactions to
;            work correctly. In most cases, having exact ranges is what
;            is desired anyway.
;
; CALLING SEQUENCE:
;
;      eCONTOUR, z, [x, y]
;
; ARGUMENTS:
;
;     Z:            Two dimensional array containing the data values
;                   to contour.
;
;     X:            Either a vector or a 2D array containing the X
;                   coordinates of the Z data. If not provided, it is
;                   set to FINDGEN(nx) where nx is the number of columns
;                   in the Z array.
;                   
;
;     Y:            Either a vector or a 2D array containing the Y
;                   coordinates of the Z data. If not provided, it is
;                   set to FINDGEN(ny) where ny is the number of rows
;                   in the Z array.
;
;                 
; KEYWORD PARAMETERS:
;
;     AUTOSCALE:    *IGL ADDITION * : Use this keyword in conjunction with the OVERPLOT
;                   keyword. If set, the axis coordinate system on
;                   which the contour is overplotted will be
;                   autoscaled.
;
;     AXISCOLOR:    The name of the color for the X and Y axis. The
;                   default is !IGL_P.Axiscolor
;
;     BACKGROUND:   The name of the background color. The default is
;                   !IGL_P.background
;
;     CELL_FILL:    Set this keyword to produce a filled contour using
;                   a cell filling algorithm.
;
;     CHARSIZE:     The character size for the annotations (float). The default
;                   is !IGL_P.charsize
;
;     CHARTHICK:    The character thickness for the annotations (integer). The
;                   default is !IG_P.charthick
;
;     COLOR:        The name of the foreground color for the plot. The
;                   default is !IGL_P.color
;
;     C_ANNOTATION: Vector of strings specifying the label to draw on
;                   each contour.
;               
;     C_CHARSIZE:   Vector specifying the character size of the label annotations.
;               
;     C_CHARTHICK:  Vector specifying the character thickness of the label annotations.
;               
;     C_COLORS:     Specify the color of each contour level. You can
;                   either use color names or color indexes.
;               
;     C_LABELS:     The vector containing the flags specifying which
;                   contour levels are labeled.
;               
;     C_LINESTYLE:  Vector specifying the line style used to draw each contour.
;               
;     C_THICK:      Vector specifying the line thickness used to draw
;                   each contour.             
;
;     CLOSED:       Set this keyword to close contours at the plot boundaries.
;               
;     DOWNHILL:     Set this keyword to draw tick marks in the
;                   downhill direction on each contour.
;
;     FILL:         Set this keyword to produce a filled contour plot.
;
;     FONT:         The character font for the annotations(integer).
;                   -1 : Herschey, 0 : Hardware, 1 : True Type. The
;                   default is !IGL_P.font
;
;     LEVELS:       Vector specifying the contour levels to draw.
;
;     NLEVELS:      The number of contour levels to produce. Used only
;                   if levels are not specified with the LEVELS
;                   keyword. Note that contrary to the IDL CONTOUR
;                   command, this produces the correct number of levels.
;
;     NOCLIP:       If set, prevent the clipping at the edge of the
;                   plot window. The default is !IGL_P.noclip
;
;     NODATA:       Set this keyword to plot only the axis and the
;                   annotations.
;
;     NODRAW:       *IGL ADDITION* : Set this keyword to prevent the
;                   current window to be refreshed. The contour and axis
;                   are added to the window but they will not be
;                   visible until the window is refreshed (by calling
;                   another IGL plotting command for example). This is
;                   useful is you wish to issue several plotting
;                   commands but want to display the results only at
;                   the end. 
;
;     NOERASE:      If set, prevent the current window to be erased
;                   before drawing the plot. The default is
;                   !IGL_P.noerase
;
;     OVERPLOT:     Set this keyword to overplot the contour on
;                   an already established axis coordinate
;                   system. Note that all the axis related keywords
;                   are not taken into account when setting this option.
;
;     POSITION:     A 4-element vector indicating the position of the
;                   plot in the window in normalized coordinates. The
;                   default is !IGL_P.position
;
;     STATIC:       *IGL ADDITION* : Set this keyword to indicate that
;                   the data coordinate system associated with the
;                   plot is static. This prevents the data X and Y
;                   ranges to be changed and as a consequence, the
;                   plot cannot be panned or zoomed. Note that you can
;                   interactively change this behaviour after the
;                   plot is produced.
;
;     THICK:        The thickness of the line (integer). The default
;                   is !IGL_P.thick
;
;     TICKLEN:      Specify the length of the axis tick marks, in
;                   units of the fraction of the plot window. The
;                   default is !IGL_P.ticklen.
;
;     TITLE:        The text string used as the plot title. THe
;                   default is !IGL_P.title
;
;     [XY]CHARSIZE: The character size for the axis annotations. Be
;                   careful that this is like the regular IDL
;                   keyword meaning that it only indicates a multiplying
;                   factor to the global character size specified by
;                   the CHARSIZE keyword. The default is !IGL_[XY].charsize
;
;     [XY]GRIDSTYLE: Integer specifying the linestyle to use for the
;                    axis grid. The default is !IGL_[XY].gridstyle
;
;     [XY]LOG:      Set this keyword if you want logarithmic axis
;                   scaling.
;
;     [XY]MINOR:    The number of minor axis tick intervals. The default
;                   is !IGL_[XY].minor
;
;     [XY]RANGE:    2-element vector specifying the axis data
;                   range. The default is !IGL_[XY].range
;
;     [XY]STYLE:    Integer specifying the axis style options. Note
;                   that the "extended range" option ([XY]style=2) is
;                   disabled because it prevents pan and zoom
;                   interactions to work correctly. The default is !IGL_[XY].style
;
;     [XY]THICK:    The thickness of the line forming the axis. The
;                   default is !IGL_[XY].thick
;
;     [XY]TICKFORMAT: String specifying the format used for the axis
;                     labels. The default is !IGL_[XY].tickformat
;
;     [XY]TICKINTERVAL: Scalar indicating the interval between major
;                       tick marks. The default is !IGL_[XY].tickinterval
;
;     [XY]TICKLAYOUT: Integer specifying the axis layout. Possible
;                     values are : 0 = Normal layout, 1 = Only labels,
;                     2 = Box layout. The default is !IGL_[XY].ticklayout
;
;     [XY]TICKLEN:  The length of the axis tick marks. This overrides
;                   the global setting specified by the TICKLEN
;                   keyword. The default is !IGL_[XY].ticklen
;
;     [XY]TICKNAME: String array specifying the annotation of each
;                   tick marks. The default is !IGL_[XY].tickname
;
;     [XY]TICKS:    Integer specifying the number of major tick
;                   intervals. The default is !IGL_[XY].ticks
;
;     [XY]TICKUNITS: Vector of strings indicating the units used for
;                    axis tick labeling. The default is !IGL_[XY].tickunits
;
;     [XY]TICKV:    Array of data values for each tick mark. The
;                   default is !IGL_[XY].tickv
;
;     [XY]TITLE:    The text string used as the axis title. The
;                   default is !IGL_[XY].title
;    
; PACKAGE:
;
;    Interactive Graphics Library (IGL)
;
; AUTHORS:
;
;        RAPHAEL SADOUN
;        Graduate Student
;        Institut d'Astrophysique de Paris
;        98 bis boulevard Arago
;        75014 PARIS FRANCE
;        E-mail: raphael.sadoun@gmail.com
;
;
; MODIFICATION HISTORY:
;
;     Written by: Raphael Sadoun, 24 April 2012
;-
;*****************************************************************************************************
PRO eCONTOUR, z, x, y, $
              AUTOSCALE=autoscale, $
              AXISCOLOR=axiscolor, $
              BACKGROUND=background, $
              CELL_FILL=cell_fill, $
              CHARSIZE=charsize, $
              CHARTHICK=charthick, $
              CLOSED=closed, $
              COLOR=color, $
              C_ANNOTATION=c_annotation, $
              C_CHARSIZE=c_charsize, $
              C_CHARTHICK=c_charthick, $
              C_COLORS=c_colors, $
              C_LABELS=c_labels, $
              C_LINESTYLE=c_linestyle, $
              C_THICK=c_thick, $
              DOWNHILL=downhill, $
              FILL=fill, $
              FONT=font, $
              LEVELS=levels, $
              NLEVELS=nlevels, $
              NOCLIP=noclip, $
              NODATA=nodata, $
              NODRAW=nodraw, $
              NOERASE=noerase, $
              OVERPLOT=overplot, $
              POSITION=position, $
              STATIC=static, $
              THICK=thick, $
              TICKLEN=ticklen, $
              TITLE=title, $
              XCHARSIZE=xcharsize, $
              XGRIDSTYLE=xgridstyle, $
              XLOG=xlog, $
              XMINOR=xminor, $
              XRANGE=xrange, $
              XSTYLE=xstyle, $
              XTHICK=xthick, $
              XTICKFORMAT=xtickformat, $
              XTICKINTERVAL=xtickinterval, $
              XTICKLAYOUT=xticklayout, $
              XTICKLEN=xticklen, $
              XTICKNAME=xtickname, $
              XTICKS=xticks, $
              XTICKUNITS=xtickunits, $
              XTICKV=xtickv, $
              XTITLE=xtitle, $
              YCHARSIZE=ycharsize, $
              YGRIDSTYLE=ygridstyle, $
              YLOG=ylog, $
              YMINOR=yminor, $
              YRANGE=yrange, $
              YSTYLE=ystyle, $
              YTHICK=ythick, $
              YTICKFORMAT=ytickformat, $
              YTICKINTERVAL=ytickinterval, $
              YTICKLAYOUT=yticklayout, $
              YTICKLEN=yticklen, $
              YTICKNAME=ytickname, $
              YTICKS=yticks, $
              YTICKUNITS=ytickunits, $
              YTICKV=ytickv, $
              YTITLE=ytitle


  COMPILE_OPT idl2, HIDDEN
  ON_ERROR, 2

  ;; Initialize the global system variables
  IGL_InitSysVars

  ;; Check positional arguments
  CASE N_PARAMS() OF
     
     0: Message, 'No arguments passed to eCONTOUR'
     
     1: BEGIN
        zdata = z
        dims = Size(zdata)
        IF dims[0] NE 2 THEN Message, 'Array must have 2 dimensions'
        xdata = Findgen(dims[1])
        ydata = Findgen(dims[2])
     END
     
     2: Message, 'Incorrect number of arguments'

     3: BEGIN
        zdata = z
        xdata = x
        ydata = y
        zdims = Size(zdata)
        xdims = Size(xdata)
        ydims = Size(ydata)

        IF zdims[0] NE 2 THEN Message, 'Array must have 2 dimensions'

        CASE xdims[0] OF
           1: IF xdims[1] NE zdims[1] THEN Message, 'X argument has incorrect number of elements'
           2: IF (xdims[1] NE zdims[1]) OR (xdims[2] NE zdims[2]) THEN Message, 'X argument has incorrect number of elements'
           ELSE: Message, 'X argument has incorrect number of dimensions'
        ENDCASE

        CASE ydims[0] OF
           1: IF ydims[1] NE zdims[1] THEN Message, 'Y argument has incorrect number of elements'
           2: IF (ydims[1] NE zdims[1]) OR (ydims[2] NE zdims[2]) THEN Message, 'Y argument has incorrect number of elements'
           ELSE: Message, 'Y argument has incorrect number of dimensions'
        ENDCASE
        
     END

     ELSE:
     
  ENDCASE

  ;; Default keyword values

  ;; General keywords
  IF N_Elements(axiscolor) EQ 0 THEN axiscolor = !IGL_P.axiscolor
  IF N_Elements(background) EQ 0 THEN background = !IGL_P.background
  IF N_Elements(charsize) EQ 0 THEN charsize = (!IGL_P.charsize LE 0) ? 1 : !IGL_P.charsize
  IF N_Elements(charthick) EQ 0 THEN charthick = (!IGL_P.charthick LE 0) ? 1 : !IGL_P.charthick
  IF N_Elements(color) EQ 0 THEN color = !IGL_P.color
  IF N_Elements(font) EQ 0 THEN font = !IGL_P.font
  IF N_Elements(noclip) EQ 0 THEN noclip = !IGL_P.noclip
  IF N_Elements(noerase) EQ 0 THEN noerase = !IGL_P.noerase
  IF N_Elements(position) EQ 0 THEN position = !IGL_P.position
  IF N_Elements(thick) EQ 0 THEN thick = (!IGL_P.thick LE 0) ? 1 : !IGL_P.thick
  IF N_Elements(ticklen) EQ 0 THEN ticklen = (!IGL_P.ticklen LE 0) ? 0.02 : !IGL_P.ticklen
  IF N_Elements(title) EQ 0 THEN title = !IGL_P.title

  ;; X axis keywords
  IF N_Elements(xcharsize) EQ 0 THEN xcharsize = (!IGL_X.charsize LE 0) ? 1 : !IGL_X.charsize
  IF N_Elements(xgridstyle) EQ 0 THEN xgridstyle = !IGL_X.gridstyle
  IF N_Elements(xminor) EQ 0 THEN xminor = !IGL_X.minor
  IF N_Elements(xrange) EQ 0 THEN xrange = !IGL_X.range
  IF N_Elements(xstyle) EQ 0 THEN xstyle = !IGL_X.style
  IF N_Elements(xthick) EQ 0 THEN xthick = (!IGL_X.thick LE 0) ? 1 : !IGL_X.thick
  IF N_Elements(xtickformat) EQ 0 THEN xtickformat = !IGL_X.tickformat
  IF N_Elements(xtickinterval) EQ 0 THEN xtickinterval = !IGL_X.tickinterval
  IF N_Elements(xticklayout) EQ 0 THEN xticklayout = !IGL_X.ticklayout
  IF N_Elements(xticklen) EQ 0 THEN xticklen = (!IGL_X.ticklen LE 0) ? ticklen : !IGL_X.ticklen
  IF N_Elements(xtickname) EQ 0 THEN xtickname = !IGL_X.tickname
  IF N_Elements(xticks) EQ 0 THEN xticks = !IGL_X.ticks
  IF N_Elements(xtickunits) EQ 0 THEN xtickunits = !IGL_X.tickunits
  IF N_Elements(xtickv) EQ 0 THEN xtickv = !IGL_X.tickv
  IF N_Elements(xtitle) EQ 0 THEN xtitle = !IGL_X.title

  ;; Y axis keywords
  IF N_Elements(ycharsize) EQ 0 THEN ycharsize = (!IGL_Y.charsize LE 0) ? 1 : !IGL_Y.charsize
  IF N_Elements(ygridstyle) EQ 0 THEN ygridstyle = !IGL_Y.gridstyle
  IF N_Elements(yminor) EQ 0 THEN yminor = !IGL_Y.minor
  IF N_Elements(yrange) EQ 0 THEN yrange = !IGL_Y.range
  IF N_Elements(ystyle) EQ 0 THEN ystyle = !IGL_Y.style
  IF N_Elements(ythick) EQ 0 THEN ythick = (!IGL_Y.thick LE 0) ? 1 : !IGL_Y.thick
  IF N_Elements(ytickformat) EQ 0 THEN ytickformat = !IGL_Y.tickformat
  IF N_Elements(ytickinterval) EQ 0 THEN ytickinterval = !IGL_Y.tickinterval
  IF N_Elements(yticklayout) EQ 0 THEN yticklayout = !IGL_Y.ticklayout
  IF N_Elements(yticklen) EQ 0 THEN yticklen = (!IGL_Y.ticklen LE 0) ? ticklen : !IGL_Y.ticklen
  IF N_Elements(ytickname) EQ 0 THEN ytickname = !IGL_Y.tickname
  IF N_Elements(yticks) EQ 0 THEN yticks = !IGL_Y.ticks
  IF N_Elements(ytickunits) EQ 0 THEN ytickunits = !IGL_Y.tickunits
  IF N_Elements(ytickv) EQ 0 THEN ytickv = !IGL_Y.tickv
  IF N_Elements(ytitle) EQ 0 THEN ytitle = !IGL_Y.title

  ;; Check the desired contour type
  type = 0
  IF Keyword_Set(fill) THEN type = 1
  IF Keyword_Set(cell_fill) THEN type = 2

  ;; Save device settings and switch to window device
  entryDevice = !d.name
  IF (strupcase(!version.os_family) EQ 'UNIX') THEN set_plot, 'X'
  IF (strupcase(!version.os_family) EQ 'WINDOWS') THEN set_plot, 'WIN'

  ;; Get current window, create one if none is available
  currentWindow = IGL_GetCurrentWindow()
  IF OBJ_ISA_VALID(currentWindow,'IGL_WINDOW') EQ 0 THEN currentWindow = obj_new('IGL_Window')
  currentWindow -> GetProperty, Window_Xsize=Xsize, Window_Ysize=Ysize

  ;; Do we want to overplot the contour ?
  IF Keyword_Set(overplot) THEN BEGIN

     ;; If we don't want to produce the contour, then do nothing...
     IF Keyword_Set(nodata) THEN RETURN 
      
     ;; Get the current coordinate system
     currentCoords = IGL_GetSysVars('currentCoord')
     IF OBJ_ISA_VALID(currentCoords,'CatCoord') EQ 0 THEN Message, 'A coordinate system is not established'
     
     ;; Get the object that represents the coordinate system in the graphic
     currentCoords -> GetProperty, FIRST_PARENT=parent
     IF OBJ_VALID(parent) EQ 0 THEN Message, 'Invalid coordinate system'
     
     ;; Get the graphic in which the parent object is contained
     parent -> GetProperty, FIRST_PARENT=graphic
     IF OBJ_ISA_VALID(graphic,'IGL_Graphic') EQ 0 THEN message, 'Current coordinate system is not in a valid graphic'
     
     ;; Create a new contour object 
     contourObject = obj_new('IGL_Contour', $
                             ZDATA=zdata, $
                             XDATA=xdata, $
                             YDATA=ydata, $
                             C_ANNOTATION=c_annotation, $
                             C_CHARSIZE=c_charsize, $
                             C_CHARTHICK=c_charthick, $
                             C_COLORS=c_colors, $
                             C_LABELS=c_labels, $
                             C_LINESTYLE=c_linestyle, $
                             C_THICK=c_thick, $
                             CLOSED=Keyword_Set(closed), $
                             COLOR=color, $
                             FONT=font, $
                             DOWNHILL=Keyword_Set(downhill), $
                             LEVELS=levels, $
                             NLEVELS=nlevels, $
                             CLIP=(1-Keyword_Set(noclip)), $
                             THICK=thick, $
                             TYPE=type $
                            )
     contourObject -> SetProperty, Name='Ocontour', Coord_Object=currentCoords
     
     ;; Add the contour plot to the object that holds the coordinate system
     parent -> Add, contourObject
     
     ;; Do we need to autoscale ?
     IF Keyword_Set(autoscale) THEN graphic -> ZoomOut, /AllTheWay, /Nodraw     
     
  ENDIF ELSE BEGIN ; If not overplotting, then we create a new graphic and a coordinate system     

     ;; Make sure we have a valid position vector
     IF Total(position) LE 0 THEN pos = [0.1,0.1,0.9,0.9] ELSE pos = position
     IF (pos[0] GE pos[2]) OR (pos[1] GE pos[3]) THEN Message, 'Invalid POSITION array'
     
     ;; Take care of multiplots according to !IGL_P.multi. Basically, we
     ;; need to calculate the position of the plot in the window. We let
     ;; IDL do that for us by drawing a plot in a pixmap and retrieving the plot
     ;; window afterwards.
     
     multi = !IGL_P.multi
     DontErase = noerase
     
     IF (multi[1] GT 0) OR (multi[2] GT 0) THEN BEGIN ; Do we need multiple plots ?
        
        IF (multi[0] GT 0) THEN DontErase = 1 ; Only erase the window if we are the first plot of the grid
        
        ;; Save the IDL multi property and set it to the IGL value
        currentMulti = !P.multi
        !P.multi = multi
        
        ;; We create a pixmap with the same size as the current IGL window
        window, /free, /pixmap, xsize=xsize, ysize=ysize     
        wPix = !D.window
        
        ;; Advance the multi state by drawing a dummy plot
        plot, fltarr(2), xstyle=5, ystyle=5
        
        ;;  Save the plot position
        pos = [!x.window[0],!y.window[0],!x.window[1],!y.window[1]]
        
        ;; Save the new multi in the IGL variable and restore the IDL
        ;; value 
        !IGL_P.multi = !P.multi
        !P.multi = currentMulti
        
        ;; Delete the pixmap
        IF (windowAvailable(wPix)) THEN wdelete, wPix
        
     ENDIF  
  
     ;; Make sure the X and Y data ranges are valid. If not, calculate new
     ;; ones based on the minimum and maximum data values. 
     
     ;; X range
     IF (xrange[0] EQ xrange[1]) THEN xrange = [min(xdata),max(xdata)]
     
     ;; Y range
     IF (yrange[0] EQ yrange[1]) THEN yrange = [min(ydata),max(ydata)]     
     
     ;; Check the axis style options
     noXAxis = bitget(xstyle,2,/silent)
     noYAxis = bitget(ystyle,2,/silent)
     OnlyOneXaxis = bitget(xstyle,3,/silent)
     OnlyOneYaxis = bitget(ystyle,3,/silent)
     
     ;; Create a new graphic object to hold the contour plot and the axis
     graphic = obj_new('IGL_Graphic',POSITION=pos)

     ;; Initialize the coordinate system
     coords = obj_new('IGL_COORD', $
                      POSITION=pos, $
                      XRANGE=xrange, $
                      YRANGE=yrange, $
                      XLOG=Keyword_Set(xlog), $
                      YLOG=Keyword_set(ylog), $
                      STATIC=Keyword_Set(static) $
                     )

     ;; Create the contour object
     IF Keyword_Set(nodata) THEN BEGIN
        
        contourObject = obj_new('IGL_Contour', $
                                ZDATA=fltarr(2,2), $
                                XDATA=[0,0], $
                                YDATA=[0,0], $
                                C_ANNOTATION=c_annotation, $
                                C_CHARSIZE=c_charsize, $
                                C_CHARTHICK=c_charthick, $
                                C_COLORS=c_colors, $
                                C_LABELS=c_labels, $
                                C_LINESTYLE=c_linestyle, $
                                C_THICK=c_thick, $
                                CLOSED=Keyword_Set(closed), $
                                COLOR=color, $
                                FONT=font, $
                                DOWNHILL=Keyword_Set(downhill), $
                                LEVELS=levels, $
                                NLEVELS=nlevels, $
                                CLIP=(1-Keyword_Set(noclip)), $
                                THICK=thick, $
                                TYPE=type, $
                                COORD_OBJECT=coords $
                               )
     ENDIF ELSE BEGIN

        contourObject = obj_new('IGL_Contour', $
                                ZDATA=zdata, $
                                XDATA=xdata, $
                                YDATA=ydata, $
                                C_ANNOTATION=c_annotation, $
                                C_CHARSIZE=c_charsize, $
                                C_CHARTHICK=c_charthick, $
                                C_COLORS=c_colors, $
                                C_LABELS=c_labels, $
                                C_LINESTYLE=c_linestyle, $
                                C_THICK=c_thick, $
                                CLOSED=Keyword_Set(closed), $
                                COLOR=color, $
                                FONT=font, $
                                DOWNHILL=Keyword_Set(downhill), $
                                LEVELS=levels, $
                                NLEVELS=nlevels, $
                                CLIP=(1-Keyword_Set(noclip)), $
                                THICK=thick, $
                                TYPE=type, $
                                COORD_OBJECT=coords $
                               )
        
     ENDELSE

     ;; Create the contour plot title if needed
     IF (title NE '') THEN BEGIN
        
        ;; Calculate the title position
        xloc = 0.5
        yloc = pos[3]+!D.Y_CH_SIZE/float(Ysize)
        yloc = (yloc-pos[1])/(pos[3]-pos[1]) ; Convert to graphic coordinates
        
        ;; Initialize the text object
        textObject = obj_new('IGL_Text',title, $
                             X=xloc, $
                             Y=yloc, $
                             ALIGNMENT=1, $
                             CHARSIZE=1.25*charsize, $
                             CLIP=0, $
                             COLOR=axiscolor, $
                             FONT=(font+1), $
                             THICKNESS=charthick, $
                             ORIENTATION=0.0 $
                            )
        
        ;; Get the graphic's coordinate system to assign it to the text object
        graphic -> GetProperty, Coord_Object=graphicCoords
        
        ;; Set object properties
        textObject -> SetProperty, Name='Title', Coord_Object=graphicCoords
        
        ;; Add the title to the plot
        contourObject -> Add, textObject
        
     ENDIF

     ;; Create the axis     

     ;; X AXIS
     IF noXAxis EQ 0 THEN BEGIN ; We need at least the bottom axis
        
        bottomAxis = obj_new('IGL_Axis', $
                             COORD_OBJECT=coords, $
                             XLOC=0.0, $
                             YLOC=0.0, $
                             DIRECTION=0, $
                             TICKDIR=0, $
                             COLOR=axiscolor, $
                             CHARSIZE=(xcharsize*charsize), $
                             CHARTHICK=charthick, $
                             FONT=(font+1), $
                             GRIDSTYLE=xgridstyle, $
                             THICK=xthick, $
                             MINOR=xminor, $
                             TICKFORMAT=xtickformat, $
                             TICKNAME=xtickname, $
                             TICKINTERVAL=xtickinterval, $
                             TICKLAYOUT=xticklayout, $
                             TICKLEN=xticklen, $
                             TICKS=xticks, $
                             TICKUNITS=xtickunits, $
                             TICKV=xtickv $
                            )

        ;; Create the axis title if needed
        IF (xtitle NE '') THEN BEGIN

           ;; Calculate the title position
           xloc = 0.5
           yloc = pos[1]-3.0*charsize*xcharsize*!D.Y_CH_SIZE/float(Ysize)
           yloc = (yloc-pos[1])/(pos[3]-pos[1]) ; Convert to graphic coordinates
           
           ;; Initialize the text object
           textObject = obj_new('IGL_Text',xtitle, $
                                X=xloc, $
                                Y=yloc, $
                                ALIGNMENT=1, $
                                CHARSIZE=charsize*xcharsize, $
                                CLIP=0, $
                                COLOR=axiscolor, $
                                FONT=(font+1), $
                                THICKNESS=charthick, $
                                ORIENTATION=0.0 $
                               )

           ;; Get the graphic's coordinate system to assign it to the text object
           graphic -> GetProperty, Coord_Object=graphicCoords

           ;; Set object properties
           textObject -> SetProperty, Name='Axis Title', Coord_Object=graphicCoords

           ;; Add the title to the axis
           bottomAxis -> Add, textObject
     
        ENDIF                        

        ;; Add the axis to the contour plot
        contourObject -> Add, bottomAxis

        IF OnlyOneXaxis EQ 0 THEN BEGIN ; We need the top axis

           topAxis = obj_new('IGL_Axis', $
                             COORD_OBJECT=coords, $
                             XLOC=0.0, $
                             YLOC=1.0, $
                             DIRECTION=0, $
                             TICKDIR=1, $
                             COLOR=axiscolor, $
                             CHARSIZE=(xcharsize*charsize), $
                             CHARTHICK=charthick, $
                             FONT=(font+1), $
                             GRIDSTYLE=xgridstyle, $
                             THICK=xthick, $
                             MINOR=xminor, $
                             TICKFORMAT='(A1)', $
                             TICKNAME=xtickname, $
                             TICKINTERVAL=xtickinterval, $
                             TICKLAYOUT=xticklayout, $
                             TICKLEN=xticklen, $
                             TICKS=xticks, $
                             TICKUNITS=xtickunits, $
                             TICKV=xtickv $
                            )

           ;; Add the axis to the contour plot
           contourObject -> Add, topAxis
           
        ENDIF

     ENDIF

     ;; Y AXIS
     IF noYAxis EQ 0 THEN BEGIN ; We need at least the left axis

        leftAxis = obj_new('IGL_Axis', $
                           COORD_OBJECT=coords, $
                           XLOC=0.0, $
                           YLOC=0.0, $
                           DIRECTION=1, $
                           TICKDIR=0, $
                           COLOR=axiscolor, $
                           CHARSIZE=(ycharsize*charsize), $
                           CHARTHICK=charthick, $
                           FONT=(font+1), $
                           GRIDSTYLE=ygridstyle, $
                           THICK=ythick, $
                           MINOR=yminor, $
                           TICKFORMAT=ytickformat, $
                           TICKNAME=ytickname, $
                           TICKINTERVAL=ytickinterval, $
                           TICKLAYOUT=yticklayout, $
                           TICKLEN=yticklen, $
                           TICKS=yticks, $
                           TICKUNITS=ytickunits, $
                           TICKV=ytickv $
                          )

        ;; Create the axis title if needed
        IF (ytitle NE '') THEN BEGIN

           ;; Calculate the title position
           yloc = 0.5
           middle = 0.5*(yrange[1]+yrange[0])
           IF middle NE 0 THEN ndigits = Floor(alog10(Abs(middle))+1) ELSE ndigits = 1
           xloc = pos[0]-(ndigits+2.5)*charsize*ycharsize*!D.X_CH_SIZE/float(Xsize)
           xloc = (xloc-pos[0])/(pos[2]-pos[0]) ; Convert to graphic coordinates
           
           ;; Initialize the text object
           textObject = obj_new('IGL_Text',ytitle, $
                                X=xloc, $
                                Y=yloc, $
                                ALIGNMENT=1, $
                                CHARSIZE=charsize*ycharsize, $
                                CLIP=0, $
                                COLOR=axiscolor, $
                                FONT=(font+1), $
                                THICKNESS=charthick, $
                                ORIENTATION=90.0 $
                               )

           ;; Get the graphic's coordinate system to assign it to the text object
           graphic -> GetProperty, Coord_Object=graphicCoords

           ;; Set object properties
           textObject -> SetProperty, Name='Axis Title', Coord_Object=graphicCoords

           ;; Add the title to the axis
           leftAxis -> Add, textObject
     
        ENDIF                        

        ;; Add the axis to the contour plot
        contourObject -> Add, leftAxis

        IF OnlyOneYaxis EQ 0 THEN BEGIN ; We need the right axis

           rightAxis = obj_new('IGL_Axis', $
                               COORD_OBJECT=coords, $
                               XLOC=1.0, $
                               YLOC=0.0, $
                               DIRECTION=1, $
                               TICKDIR=1, $
                               COLOR=axiscolor, $
                               CHARSIZE=(ycharsize*charsize), $
                               CHARTHICK=charthick, $
                               FONT=(font+1), $
                               GRIDSTYLE=ygridstyle, $
                               THICK=ythick, $
                               MINOR=yminor, $
                               TICKFORMAT='(A1)', $
                               TICKNAME=ytickname, $
                               TICKINTERVAL=ytickinterval, $
                               TICKLAYOUT=yticklayout, $
                               TICKLEN=yticklen, $
                               TICKS=yticks, $
                               TICKUNITS=xtickunits, $
                               TICKV=ytickv $
                              )

           ;; Add the axis to the contour plot
           contourObject -> Add, rightAxis
           
        ENDIF

     ENDIF

     ;; Update the coordinate system
     IGL_SetSysVars, 'currentCoord', coords

     ;; Add the contour plot to the graphic
     graphic -> Add, contourObject

     ;; Erase the window
     IF Keyword_Set(DontErase) EQ 0 THEN BEGIN
        currentWindow -> SetProperty, Window_Color=Background
        currentWindow -> ClearWindow, /NoRefresh
     ENDIF

     ;; Add the graphic to the window
     currentWindow -> AddGraphic, graphic

  ENDELSE

  ;; Refresh the property editor
  currentWindow -> GetProperty, PropertyPanel=PropertyPanel
  IF OBJ_VALID(PropertyPanel) THEN PropertyPanel -> UpdateTreeBrowser
  
  ;; Draw window's content
  IF Keyword_set(nodraw) EQ 0 THEN currentWindow -> DrawWindow, /Buffered_Output

  ;; Restore device
  Set_Plot, entryDevice

END
